#![allow(non_snake_case)]
use crate::components::server_data_table::{ServerDataTable, TableToolbar};
use crate::components::server_error::ServerError;
use crate::components::DataEdit;
use crate::components::{EditColumn, EditMode};
use crate::layout::menu_state::MenuState;
use crate::workflow::flow_run_step::FlowRunStep;
use icondata as i;
use leptos::prelude::*;
use leptos::task::spawn_local;
use leptos_icons::*;
use serde_json::{Map, Value};
use shq_common::prelude::{Column, CommonPage, Position, SubmitType, TaskType};
use shq_web_controls::{
    use_message, ConfirmButton, MessageOptions, MessageVariant, SelectOption, SelectRaw, TableState,
};
use thaw_utils::ArcOneCallback;
#[component]
pub fn FlowRunList(
    menu_id: u32,
    #[prop(into)] wfid: u32,
    #[prop(optional, into)] edit_mode: RwSignal<EditMode>,
    #[prop(optional)] on_row_select_change: Option<ArcOneCallback<Option<Map<String, Value>>>>,
    #[prop(optional)] is_custom_create: bool,
) -> impl IntoView {
    let menu_state = use_context::<RwSignal<MenuState>>().unwrap();
    let sel_row_ids: RwSignal<Vec<u64>> = RwSignal::new(Vec::new());
    let edit_row_data: RwSignal<Option<Value>> = RwSignal::new(None);
    let is_refresh: RwSignal<bool> = RwSignal::new(false);
    let flow_task_type: RwSignal<TaskType> = RwSignal::new(TaskType::Doing);
    let display_process: RwSignal<bool> = RwSignal::new(false);
    let conf = Resource::new(
        move || wfid,
        move |wfid| async move {
            let jval_res = get_flow_page_config(menu_id, wfid).await;
            jval_res
        },
    );
    Effect::new(move || {
        if edit_mode.get() == EditMode::None {
            is_refresh.set(true);
        }
    });
    let can_export = menu_state
        .with_untracked(|ms| ms.has_auth_type(menu_id, shq_common::prelude::AuthType::Export));
    let page_view = move || {
        let on_row_select_change = on_row_select_change.clone();
        match conf.get() {
            None => either_of::EitherOf3::A(view! { <p>"Loading..."</p> }),
            Some(mv_res) => match mv_res {
                Ok(conf) => {
                    let conf_name = StoredValue::new(conf.conf_name.clone());
                    let title = StoredValue::new(
                        conf.page_conf
                            .title
                            .clone()
                            .unwrap_or("流程列表".to_string()),
                    );
                    let fps = StoredValue::new(conf.page_conf.field_props.clone());
                    let pk_name = fps.with_value(|fp| {
                        fp.iter()
                            .find(|c| c.is_pk)
                            .map(|c| c.name.as_ref().map(|n| n.to_string()))
                            .flatten()
                            .expect("配置中必须有主键")
                    });
                    let pk_name = StoredValue::new(pk_name);
                    let list_view = if let Some(list_props) = conf.page_conf.list_props.clone() {
                        let list_props = StoredValue::new(list_props);
                        let set_row_date = move |row_datas: Vec<(usize, Value)>| {
                            let pk_name = pk_name.get_value();
                            if !row_datas.is_empty() {
                                let v = row_datas[row_datas.len() - 1].1.clone();
                                let mut ids: Vec<u64> = Vec::new();
                                for (_idx, v) in row_datas {
                                    if let Some(pk_val) = v.get(&pk_name) {
                                        if let Some(id) = pk_val.as_u64() {
                                            ids.push(id);
                                        }
                                    }
                                }
                                if let Some(on_row_select_change) = on_row_select_change.as_ref() {
                                    if let Some(mv) = v.as_object() {
                                        (on_row_select_change)(Some(mv.clone()));
                                    }
                                }
                                edit_row_data.set(Some(v));
                                sel_row_ids.set(ids);
                            } else {
                                edit_row_data.set(None);
                                sel_row_ids.set(Vec::new());
                                if let Some(on_row_select_change) = on_row_select_change.as_ref() {
                                    (on_row_select_change)(None);
                                }
                            }
                        };
                        Some(view! {
                            <ServerDataTable menu_id conf_name=conf_name.get_value() title=title.get_value() list_props field_props=fps on_select_change=set_row_date can_export is_refresh flow_task_type=flow_task_type>
                                <TableToolbar slot>
                                    <Toolbar
                                        menu_id
                                        conf_name=conf_name
                                        title=title
                                        edit_row_data
                                        edit_mode=edit_mode
                                        sel_row_ids=sel_row_ids
                                        is_refresh=is_refresh
                                        display_process=display_process
                                        can_create=conf.can_create
                                        is_manager=conf.is_manager
                                        flow_task_type
                                        title_col_names=StoredValue::new(conf.title_col_names.clone())
                                    />
                                </TableToolbar>
                            </ServerDataTable>
                        })
                    } else {
                        None
                    };
                    let edit_view = if !is_custom_create
                        && conf.can_create
                        && conf.page_conf.form_props.is_some()
                    {
                        let form_props = conf.page_conf.form_props.as_ref().unwrap();
                        let conf_name = Some(conf_name.get_value());
                        let title = title.get_value();
                        fps.with_value(|fp| {
                            let width = form_props.width;
                            let title = Some(title.to_string());
                            let position = Position::Modal;
                            let layout = form_props.layout.clone();
                            let conf_name = conf_name.map(|d| d.to_string());
                            let mut edit_cols: Vec<EditColumn> = Vec::new();
                            get_edit_columns(fp, &mut edit_cols);
                            Some(view! {
                                <DataEdit menu_id title position layout max_width=width conf_name edit_mode=edit_mode field_props=StoredValue::new(edit_cols) row_data=edit_row_data/>
                            })
                        })
                    } else {
                        None
                    };
                    either_of::EitherOf3::B(view! {
                        {list_view}
                        {edit_view}
                    })
                }
                Err(err) => {
                    either_of::EitherOf3::C(view! { <ServerError err_msg=err.to_string().into()/> })
                }
            },
        }
    };
    view! {
        <div class="flex-1 flex flex-col m-full h-full space-y-1 overflow-hidden">
            <Suspense fallback=|| view! { <progress class="progress w-56"></progress> }>
                {page_view}
            </Suspense>
        </div>
    }
}

struct SelectProps {
    run_ids: StoredValue<Vec<u64>>,
    can_back: bool,
    can_take_back: bool,
    can_suspend: bool,
    can_delete: bool,
    title: String,
}

#[component]
fn Toolbar(
    menu_id: u32,
    conf_name: StoredValue<String>,
    title: StoredValue<String>,
    edit_row_data: RwSignal<Option<Value>>,
    edit_mode: RwSignal<EditMode>,
    sel_row_ids: RwSignal<Vec<u64>>,
    flow_task_type: RwSignal<TaskType>,
    is_refresh: RwSignal<bool>,
    display_process: RwSignal<bool>,
    title_col_names: StoredValue<Vec<String>>,
    can_create: bool,
    is_manager: bool,
) -> impl IntoView {
    let mess = use_message();
    let table_state =
        use_context::<ReadSignal<TableState>>().expect("ReadSignal<TableState>在上下文中不存在");
    let list_data = table_state.with_untracked(|ts| ts.list_data().read_only());
    let sel_props = move || {
        list_data.with_untracked(|ld| {
            let sel_row_ids = table_state.with_untracked(|ts| ts.selected_indexs().get());
            let mut can_back = true;
            let mut can_take_back = true;
            let mut can_suspend = true;
            let mut can_delete = true;
            let mut run_ids: Vec<u64> = Vec::new();
            let mut title: String = String::new();
            for id in sel_row_ids.into_iter() {
                if let Some(r) = ld.get(id as usize).map(|v|v.as_object()).flatten() {
                    let run_id = r.get("frid").and_then(|v| v.as_u64()).unwrap_or(0);
                    run_ids.push(run_id);
                    if can_delete {
                        can_delete = r
                            .get("can_delete")
                            .and_then(|v| v.as_bool())
                            .unwrap_or(false);
                    }
                    if can_take_back {
                        can_take_back = r
                            .get("can_take_back")
                            .and_then(|v| v.as_bool())
                            .unwrap_or(false);
                    }
                    if can_suspend {
                        can_suspend = r
                            .get("can_suspend")
                            .and_then(|v| v.as_bool())
                            .unwrap_or(false);
                    }
                    if can_back {
                        can_back = r.get("can_back").and_then(|v| v.as_bool()).unwrap_or(false);
                    }
                    title_col_names.with_value(|cnames| {
                        for c in cnames.iter() {
                            if let Some(v) = r.get(c) {
                                if let Some(s) = v.as_str() {
                                    title.push_str(s);
                                }
                            }
                        }
                    });
                }
            }
            if run_ids.is_empty() {
                can_back = false;
                can_take_back = false;
                can_suspend = false;
                can_delete = false;
            }
            SelectProps {
                run_ids: StoredValue::new(run_ids),
                can_back,
                can_take_back,
                can_suspend,
                can_delete,
                title,
            }
        })
    };
    let task_type_view = move || {
        let mut vals: Vec<(u8, &str)> = vec![(0, "我的待办"), (1, "我的已办"), (3, "已完结")];
        if is_manager {
            vals.push((4, "我管理的"));
        }
        let item = vals.iter().find(|(v, _)| *v == flow_task_type.get() as u8);
        let options = vals
            .iter()
            .map(|(v, label)| SelectOption {
                label: label.to_string(),
                value: *v,
            })
            .collect::<Vec<SelectOption<u8>>>();
        let label = item.map(|(_, l)| l.to_string());
        let on_select = ArcOneCallback::new(move |val: Option<u8>| {
            sel_row_ids.set(Vec::new());
            flow_task_type.set(val.unwrap_or(0).into());
        });
        view! {
            <SelectRaw values=vec![flow_task_type.get() as u8]
                    options
                    on_select
            >
                    <div class="btn" style="width:120px">
                        {label}
                        <Icon icon=i::AiDownOutlined/>
                    </div>
            </SelectRaw>
        }
    };
    let buttons_view = move || {
        let sp = sel_props();
        let count = sp.run_ids.with_value(|v| v.len());
        view! {
            {if flow_task_type.with(|f| *f == TaskType::Doing) && count>0 {
                Some(view! {<ConfirmButton text="提交" message=format!("您确认要提交选中{count}个流程吗？") class="btn btn-primary"
                    on_click=move|| {
                        if sel_row_ids.with(|d| d.is_empty()) {
                            mess.create("请选择要提交流程", MessageVariant::Error, MessageOptions::default());
                            return false;
                        }
                        true
                    }
                    on_ok=move|_|{
                        spawn_local(async move {
                            let res = flow_submit(menu_id, sp.run_ids.get_value(), SubmitType::SendNext, None, false).await;
                            match res {
                                Ok(_) => {
                                    is_refresh.set(true);
                                    sel_row_ids.set(Vec::new());
                                    mess.create(format!("成功提交{}个流程", sp.run_ids.with_value(|v| v.len())), MessageVariant::Success, MessageOptions::default());
                                }
                                Err(err) => {
                                    mess.create(format!("提交流程出错:{}", err), MessageVariant::Error, MessageOptions::default());
                                }
                            }
                        })
                    }/>}
                )
            }else{
                None
            }}
            {if sp.can_take_back || (is_manager && flow_task_type.with(|f| *f == TaskType::Manager) && count>0) {
                Some(view! {<ConfirmButton text="强制提交" message=format!("强制提交将跳过所有未完成的步骤，并完结流程；您确认要强制提交选中{}个流程吗？请填写原因", count) class="btn btn-primary"
                    on_click=move|| {
                        if sel_row_ids.with(|d| d.is_empty()) {
                            mess.create("请选择要强制提交流程", MessageVariant::Error, MessageOptions::default());
                            return false;
                        }
                        true
                    }
                    on_ok=move|_|{
                        spawn_local(async move {
                            let res = flow_submit(menu_id, sp.run_ids.get_value(), SubmitType::Completed, None, true).await;
                            match res {
                                Ok(_) => {
                                    is_refresh.set(true);
                                    sel_row_ids.set(Vec::new());
                                    mess.create(format!("成功强制提交{}个流程", count), MessageVariant::Success, MessageOptions::default());
                                }
                                Err(err) => {
                                    mess.create(format!("强制提交流程出错:{}", err), MessageVariant::Error, MessageOptions::default());
                                }
                            }
                        })
                    }/>}
                )
            }else{
                None
            }}
            {if sp.can_take_back || (is_manager && flow_task_type.with(|f| *f == TaskType::Manager) && count>0) {
                Some(view! {<ConfirmButton text="撤回" message=format!("您确认要撤回选中{}个流程吗？", count) class="btn btn-primary"
                    on_click=move|| {
                        if sel_row_ids.with(|d| d.is_empty()) {
                            mess.create("请选择要撤回流程", MessageVariant::Error, MessageOptions::default());
                            return false;
                        }
                        true
                    }
                    on_ok=move|_|{
                        spawn_local(async move {
                            let res = flow_submit(menu_id, sp.run_ids.get_value(), SubmitType::TakeBack, None, false).await;
                            match res {
                                Ok(_) => {
                                    is_refresh.set(true);
                                    sel_row_ids.set(Vec::new());
                                    mess.create(format!("成功撤回{}个流程", sp.run_ids.with_value(|v| v.len())), MessageVariant::Success, MessageOptions::default());
                                }
                                Err(err) => {
                                    mess.create(format!("撤回流程出错:{}", err), MessageVariant::Error, MessageOptions::default());
                                }
                            }
                        })
                    }/>}
                )
            }else{
                None
            }}
            {if sp.can_back {
                Some(view! {<ConfirmButton text="退回" message=format!("您确认要退回选中{}个流程吗？请填写原因", count) class="btn btn-primary" is_feedback=true
                    on_click=move|| {
                        if sel_row_ids.with(|d| d.is_empty()) {
                            mess.create("请选择要退回行", MessageVariant::Error, MessageOptions::default());
                            return false;
                        }
                        true
                    }
                    on_ok=move|feedback|{
                        spawn_local(async move {
                            let res = flow_submit(menu_id, sp.run_ids.get_value(), SubmitType::SendBack, feedback, false).await;
                            match res {
                                Ok(_) => {
                                    is_refresh.set(true);
                                    sel_row_ids.set(Vec::new());
                                    mess.create(format!("成功退回{}个流程", sp.run_ids.with_value(|v| v.len())), MessageVariant::Success, MessageOptions::default());
                                }
                                Err(err) => {
                                    mess.create(format!("退回流程出错:{}", err), MessageVariant::Error, MessageOptions::default());
                                }
                            }
                        })
                    }/>}
                )
            }else{
                None
            }}
            {if sp.can_suspend {
                Some(view! {<ConfirmButton text="中止" message=format!("您确认要中止选中{}个流程吗？请填写原因", count) class="btn btn-primary" is_feedback=true
                    on_click=move|| {
                        if sel_row_ids.with(|d| d.is_empty()) {
                            mess.create("请选择要中止的流程", MessageVariant::Error, MessageOptions::default());
                            return false;
                        }
                        true
                    }
                    on_ok=move|feedback|{
                        spawn_local(async move {
                            let res = flow_submit(menu_id, sp.run_ids.get_value(), SubmitType::Suspend, feedback, false).await;
                            match res {
                                Ok(_) => {
                                    is_refresh.set(true);
                                    sel_row_ids.set(Vec::new());
                                    mess.create(format!("成功中止{}个流程", sp.run_ids.with_value(|v| v.len())), MessageVariant::Success, MessageOptions::default());
                                }
                                Err(err) => {
                                    mess.create(format!("中止流程出错:{}", err), MessageVariant::Error, MessageOptions::default());
                                }
                            }
                        })
                    }/>}
                )
            }else{
                None
            }}
        }
    };
    let buttons2_view=move||{
        let sp = sel_props();
        let count = sp.run_ids.with_value(|v| v.len());
        view! {
            {if can_create {
                Some(view! {<button class="btn btn-primary" on:click=move|_|{
                    edit_row_data.set(None);
                    edit_mode.set(EditMode::Add)
                }>新增</button>})
            }else{
                None
            }}
            {if can_create&&sp.can_delete&&count>0 {
                Some(view! {<ConfirmButton text="删除" message="您确认要删除选中的行吗？" class="btn btn-primary"
                    on_click=move|| {
                        if sel_row_ids.with(|d| d.is_empty()) {
                            mess.create("请选择要删除流程", MessageVariant::Error, MessageOptions::default());
                            return false;
                        }
                        true
                    }
                    on_ok=move|_|{
                        spawn_local(async move {
                            let res = delete_data_by_ids(menu_id,conf_name.get_value(),sel_row_ids.get()).await;
                            match res {
                                Ok(pk_id) => {
                                    is_refresh.set(true);
                                    sel_row_ids.set(Vec::new());
                                    mess.create(format!("成功删除{}条数据", pk_id), MessageVariant::Success, MessageOptions::default());
                                }
                                Err(err) => {
                                    mess.create(format!("删除数据出错:{}", err), MessageVariant::Error, MessageOptions::default());
                                }
                            }
                        })
                    }/>}
                )
            }else{
                None
            }}
            <button class="btn btn-primary" on:click=move|_|{
                    display_process.set(true);
                }>查看进度</button>
        }
    };
    let process_view = move || {
        if display_process.get() {
            let sp = sel_props();
            if sp.run_ids.with_value(|ids| ids.is_empty()) {
                mess.create("请选择要查看进度的流程", MessageVariant::Error, MessageOptions::default());
                return None;
            }
            let run_id = Signal::derive(move || {
                sp.run_ids
                    .with_value(|ids| ids.last().cloned().unwrap_or(0))
            });
            Some(view! { <FlowRunStep title=sp.title.clone() run_id is_show=display_process/> })
        } else {
            None
        }
    };
    view! {
        <div class="flex-none navbar bg-base-100 rounded-t-lg">
            <div class="navbar-start">
                <a class="btn btn-ghost normal-case text-base">{title.get_value()}</a>
            </div>
            <div class="navbar-center flex gap-4">
                {task_type_view}
                {buttons_view}
            </div>
            <div class="navbar-end flex gap-4">
                {buttons2_view}
            </div>
        </div>
        {process_view}
    }
}

fn get_edit_columns(field_props: &Vec<Column>, edit_cols: &mut Vec<EditColumn>) {
    for c in field_props {
        if c.children.is_empty() {
            if c.is_pk || c.edit_props.is_none() {
                continue;
            }
            let edit_col = EditColumn::new(
                c.name.as_ref().map(|n| n.to_string()).unwrap(),
                c.data_type,
                c.title.clone().unwrap_or("".to_string()),
                c.edit_props.as_ref().map(|e| e.clone()).unwrap(),
            );
            edit_cols.push(edit_col);
        } else {
            get_edit_columns(&c.children, edit_cols);
        }
    }
}
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
pub struct FlowPageConfig {
    conf_name: String,
    can_create: bool,
    page_conf: CommonPage,
    is_manager: bool,
    title_col_names: Vec<String>,
}

#[server(GetFlowPageConfig, "/api/protect")]
pub async fn get_flow_page_config(
    menu_id: u32,
    wfid: u32,
) -> Result<FlowPageConfig, ServerFnError> {
    use crate::auth::get_user_context_with_auth;
    let user = get_user_context_with_auth(menu_id, shq_common::prelude::AuthType::Select).await?;
    let (wf, _) = shq_workflow::get_workflow_newest_config(wfid)
        .ok_or(ServerFnError::new(format!("未找到工作流配置: {}", wfid)))?;
    let ps = shq_pas_backend::PageService::new(&wf.table_name, user.user_id, menu_id);
    let res = ps.get_config().await;
    let is_manager = wf
        .is_manager(user.user_id)
        .await
        .or_else(|e| Err(ServerFnError::new(format!("获取工作流管理者失败: {}", e))))?;
    match res {
        Ok(conf) => Ok(FlowPageConfig {
            conf_name: wf.table_name.to_string(),
            can_create: wf.can_create,
            page_conf: conf,
            is_manager,
            title_col_names: wf.title_col_names.clone(),
        }),
        Err(e) => Err(ServerFnError::ServerError(e.to_string())),
    }
}

#[server(FlowSubmit, "/api/protect")]
pub async fn flow_submit(
    menu_id: u32,
    run_ids: Vec<u64>,
    submit_type: SubmitType,
    feed_back: Option<String>,
    is_manager: bool,
) -> Result<(), ServerFnError> {
    use crate::auth::get_user_context_with_auth;
    let user = get_user_context_with_auth(menu_id, shq_common::prelude::AuthType::Select).await?;
    let res =
        shq_workflow::submit_batch(run_ids, user.user_id, submit_type, feed_back, is_manager).await;
    match res {
        Ok(_) => Ok(()),
        Err(e) => Err(ServerFnError::ServerError(e.to_string())),
    }
}

#[server(DeleteData, "/api/protect")]
pub async fn delete_data_by_ids(
    menu_id: u32,
    conf_name: String,
    ids: Vec<u64>,
) -> Result<u64, ServerFnError> {
    use crate::auth::get_user_context_with_auth;
    let user = get_user_context_with_auth(menu_id, shq_common::prelude::AuthType::Delete).await?;
    let ps = shq_pas_backend::PageService::new(&conf_name, user.user_id, menu_id);
    let res = ps.delete_by_ids(ids.as_slice()).await;
    match res {
        Ok(count) => Ok(count),
        Err(e) => Err(ServerFnError::ServerError(e.to_string())),
    }
}
